<?php
/*
  +----------------------------------------------------------------------+
  | UCLibCache.php                                                          |
  +----------------------------------------------------------------------+
  | Copyright (c) 2010 snda.com - Web Development Center                 |
  +----------------------------------------------------------------------+
  | Memcache engine                                                      |
  +----------------------------------------------------------------------+
  | Authors: Terry <leo9127@163.com>                                     |
  +----------------------------------------------------------------------+
*/

/**
  * 例子
  *  $cache = new $SDCache("twitter"); // 创建一个cache实例
  *  $result = $cache->read(MY_KEY); // 读取MY_KEY的值，此时连接会自动建立和关闭
  *
  * 如果对cache需要有多次操作，建议将auto_close设置为false, 这样在操作的时候不会每次都建立和关闭连接
  * 但是注意一定要在操作完成之后主动调用close函数关闭！！！
  *  $cache = new $SDCache("twitter", false); // 创建一个cache实例，设置auto_close为false
  *  $result = $cache->read(MY_KEY1); // 读取
  *  $result = $cache->read(MY_KEY2);
  *  $result = $cache->write(MY_KEY1, MY_VALUE); // 设置
  *  ... ... ... ...
  *  $result = $cache->read(MY_KEYN);
  *  $cache->close(); // 关闭连接
  */

defined('MCACHE_DEBUG')  || define('MCACHE_DEBUG', false);

class UCLibCache{
	protected $_const_server;
	protected $_host;
	protected $_conn = null;
	protected $_auto_close;
	
	function __construct($const_server, $auto_close = true) {
		require_once(dirname(__FILE__).'/UCLibLogger.php');
		if ($const_server) {
			$this->_const_server = $const_server;
		}
		$this->_auto_close = $auto_close;
        
        $hash_strategy = 'consistent';
        $hash_function = 'fnv';
		/*******************************/
		/* 控制将key映射到server的策略。*/
		/*"standard"表示使用先前版本的老hash*/
		/*策略,默认值为"consistent"可以允许在*/
		/*连接池中添加/删除服务器时不必重新计算 key与server之间的映射关系。*/
		/*******************************/
		ini_set("memcache.hash_strategy", $hash_strategy);
		/*******************************/
		/* 控制将key映射到server的散列函数*/
		/****默认值"crc32"使用CRC32算法****/
		/****而"fnv"则表示使用FNV-1a算法***/
		/*FNV-1a比CRC32速度稍低，但是散列效果更好*/
		/*******************************/
		ini_set("memcache.hash_function", $hash_function);
	}
	
	function __destruct() {
		$this->close();
	}
		
	
	/**********依照服务号选择对应的Memcache服务器*************/
	protected function cacheServer() {
		$chand = array('comment','twitter','medal','task','visitors','msg','invite','home','apps','friendsrequest','search','spread','activeuser','apppanel','applog','store','appstore','graph','ucprofile');
		if(!in_array($this->_const_server,$chand)){
			trigger_error("config [{$this->_const_server}] not existed");
			return;
		}
		$ret = array();
		if(__UC_ENV == 'DEV') {
			$ret = array(
				array('host' => '10.129.128.12', 'port' => 11556)
			);
			return $ret;
		}else if(__UC_ENV == 'TEST'){
			$ret = array(
				array('host' => '10.10.85.5', 'port' => 11556)
			);
			return $ret;
		}
		$cacheHost = array(
			array('host' => '10.150.30.11', 'port' => 11551),
			array('host' => '10.150.30.12', 'port' => 11551),
			array('host' => '10.150.30.13', 'port' => 11551),
			array('host' => '10.150.30.14', 'port' => 11551),
			array('host' => '10.150.30.15', 'port' => 11551),
			array('host' => '10.150.30.11', 'port' => 11552),
			array('host' => '10.150.30.12', 'port' => 11552),
			array('host' => '10.150.30.13', 'port' => 11552),
			array('host' => '10.150.30.14', 'port' => 11552),
			array('host' => '10.150.30.15', 'port' => 11552),
			array('host' => '10.150.30.11', 'port' => 11553),
			array('host' => '10.150.30.12', 'port' => 11553),
			array('host' => '10.150.30.13', 'port' => 11553),
			array('host' => '10.150.30.14', 'port' => 11553),
			array('host' => '10.150.30.15', 'port' => 11553),
			array('host' => '10.150.30.11', 'port' => 11554),
			array('host' => '10.150.30.12', 'port' => 11554),
			array('host' => '10.150.30.13', 'port' => 11554),
			array('host' => '10.150.30.14', 'port' => 11554),
			array('host' => '10.150.30.15', 'port' => 11554),
			array('host' => '10.150.30.11', 'port' => 11555),
			array('host' => '10.150.30.12', 'port' => 11555),
			array('host' => '10.150.30.13', 'port' => 11555),
			array('host' => '10.150.30.14', 'port' => 11555),
			array('host' => '10.150.30.15', 'port' => 11555),
			array('host' => '10.150.30.11', 'port' => 11556),
			array('host' => '10.150.30.12', 'port' => 11556),
			array('host' => '10.150.30.13', 'port' => 11556),
			array('host' => '10.150.30.14', 'port' => 11556),
			array('host' => '10.150.30.15', 'port' => 11556)
		);
		switch ($this->_const_server) {
			case 'comment': //评论频道号
			for($i=0;$i<7;$i++) {
				$ret[] = $cacheHost[$i];
			}
			break;
			case 'twitter'://微博频道号
			for($i=7;$i<14;$i++) {
				$ret[] = $cacheHost[$i];
			}
			break;
			case 'medal'://勋章频道号
			for($i=21;$i<28;$i++) {
				$ret[] = $cacheHost[$i];
			}
			break;
			case 'task'://任务频道号
			for($i=21;$i<28;$i++) {
				$ret[] = $cacheHost[$i];
			}
			break;
			case 'visitors'://访客信息
			for($i=21;$i<28;$i++) {
				$ret[] = $cacheHost[$i];
			}
			break;
			case 'msg'://消息
			for($i=21;$i<28;$i++) {
				$ret[] = $cacheHost[$i];
			}
			break;
			case 'invite'://邀请
			for($i=21;$i<28;$i++) {
				$ret[] = $cacheHost[$i];
			}
			break;
			case 'home'://HOME主页CACHE
			for($i=21;$i<28;$i++) {
				$ret[] = $cacheHost[$i];
			}
			break;
			case 'apps'://应用
			for($i=21;$i<28;$i++) {
				$ret[] = $cacheHost[$i];
			}
			break;
			case 'friendsrequest': //是否给好友发送过请求
			for($i=21;$i<28;$i++) {
				$ret[] = $cacheHost[$i];
			}
			case 'search': //搜索
			for($i=14;$i<21;$i++) {
				$ret[] = $cacheHost[$i];
			}
			break;
			case 'spread': //推广条
			for($i=21;$i<28;$i++) {
				$ret[] = $cacheHost[$i];
			}
			break;
			case 'activeuser': //活跃用户
			for($i=21;$i<28;$i++) {
				$ret[] = $cacheHost[$i];
			}
			break;
			case 'apppanel': //应用面板列表数据
			for($i=21;$i<28;$i++) {
				$ret[] = $cacheHost[$i];
			}
			break;
			case 'storelog': //谁最近玩过的应用、应用最近被谁玩过
			for($i=21;$i<28;$i++) {
				$ret[] = $cacheHost[$i];
			}
			break;
			case 'store': //应用的信息
			for($i=21;$i<28;$i++) {
				$ret[] = $cacheHost[$i];
			}
			break;
			case 'appstore': //应用的信息
			for($i=21;$i<28;$i++) {
				$ret[] = $cacheHost[$i];
			}
			break;
			case 'applog': //应用的信息
			for($i=21;$i<28;$i++) {
				$ret[] = $cacheHost[$i];
			}
			break;
			case 'graph': //graph
			for($i=21;$i<28;$i++) {
				$ret[] = $cacheHost[$i];
			}
			break;
			case 'ucprofile'://ucprofile
			for($i=0;$i<28;$i++) {
				$ret[] = $cacheHost[$i];
			}
			break;
			default:
			for($i=0;$i<28;$i++) {
				$ret[] = $cacheHost[$i];
			}
			if(MCACHE_DEBUG) {
				var_dump(func_get_args());
			 	die('cache server');
			}
			break;
		}
		return $ret;
	}
	
	/**************连接Memcache服务器**************/
	protected function connect() {
		if ($this->_conn) return $this->_conn; // 如果服务器没有关闭，直接返回

		$this->_host = $this->cacheServer();
		$this->_conn = new Memcache;
		foreach ($this->_host as &$host){
			$ret = $this->_conn->addServer($host['host'], $host['port'], false,1,3,-1);
            if( $ret === false ) {
                UCLibLogger::rpc("Connect Error@{$this->_const_server} On {$host['host']}:{$host['port']}", 5, '', '', UCLIB_LOG_RPC_TYPE_MEMCACHE);
            }
		}     
		return $this->_conn;
	}
	
	/************关闭Memcache服务器*****************/
	/*本函数为选用，addServer会在连接完成后自动断开连接*/
	public function close() {
		if ($this->_conn == null) return;
		@$this->_conn->close();
		$this->_conn = null;
	}
	
	/******************读取Memcache中的数据**************/
	public function read($key){
		if(!$key) {
			return false;
		}
		$_time_start = microtime(true);
		$this->connect();
		if ($this->_conn == null) return false;

		//批量读取
		if(is_array($key)) {
			$rows = array();
			foreach ($key as $item=>$value){
				$rows[] = $this->_conn->get($this->_const_server .'_'. $value);
			}
		}else{
			//读取单个KEY记录
			$rows = $this->_conn->get($this->_const_server.'_'.$key);
		}
		if ($this->_auto_close) $this->close();
        if( $rows === FALSE ) {
            //UCLibLogger::rpc("Read Error@{$this->_const_server}", 5, '', '', UCLIB_LOG_RPC_TYPE_MEMCACHE);
            return false;
        }
		UCLibLogger::rpc("read:".$this->_const_server.'_'.$key, microtime(true) - $_time_start, '', '', UCLIB_LOG_RPC_TYPE_MEMCACHE);
		return $rows;
	}
	
	/************批量从MEMCACHE中读取数据*************/
	public function read_multi($arraykey){
		//判断KEY是否是数组
		if(!is_array($arraykey)){
			return false;
		}
		$_time_start = microtime(true);
		$this->connect();
		if ($this->_conn == null) return false;
		$newkey = array();
		foreach($arraykey as $key=>$value){
			$newkey[] = $this->_const_server.'_'.$value;
		}
		$rows = $this->_conn->get($newkey);
		if ($this->_auto_close) $this->close();
        if( $rows === FALSE ) {
            //UCLibLogger::rpc("Read Multi Error@{$this->_const_server}", 5, '', '', UCLIB_LOG_RPC_TYPE_MEMCACHE);
            return false;
        }
		UCLibLogger::rpc("get_multi".implode(",",$newkey), microtime(true) - $_time_start, '', '', UCLIB_LOG_RPC_TYPE_MEMCACHE);
		return $rows;
	}
	
	/**************往MEMCACHE中写入数据****************/
	public function write($key, $val, $expire = 0, $flag = 0){
		if(!$key) {
			return false;
		}
		$_time_start = microtime(true);
		$this->connect();
		if ($this->_conn == null) return false;

		$ret = $this->_conn->set($this->_const_server.'_'.$key, $val, $flag, $expire);
		if ($this->_auto_close) $this->close();
        if( $ret === FALSE ) {
            UCLibLogger::rpc("Write Error@{$this->_const_server}", 5, '', '', UCLIB_LOG_RPC_TYPE_MEMCACHE);
            return false;
        }
		UCLibLogger::rpc("write:".$this->_const_server.'_'.$key, microtime(true) - $_time_start, '', '', UCLIB_LOG_RPC_TYPE_MEMCACHE);
		return $ret;
	}
	
	/******************从Memcache中删除数据*****************/
	public function delete($key,$expire = 0){
		if(!$key) {
			return false;
		}
		$_time_start = microtime(true);
		$this->connect();
		if ($this->_conn == null) return false;

		//批量删除
		if(is_array($key)){
			foreach ($key as $value){
				$ret = $this->_conn->delete($this->_const_server .'_'. $value, $expire);
			}
		} else {
			$ret = $this->_conn->delete($this->_const_server .'_'. $key, $expire);
		}
		if ($this->_auto_close) $this->close();
        
        if( $ret === FALSE ) {
            //UCLibLogger::rpc("Delete Error@{$this->_const_server}", 5, '', '', UCLIB_LOG_RPC_TYPE_MEMCACHE);
            return false;
        }
		UCLibLogger::rpc("delete:".$this->_const_server.'_'.$key, microtime(true) - $_time_start, '', '', UCLIB_LOG_RPC_TYPE_MEMCACHE);
        return true;
	}
}
?>